using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using MacomberMap.Common.User_Interfaces.Components;
using MacomberMap.Common.Internals;
using System.Data.Common;
using System.IO;
using MacomberMap.Common.Permissions;
using MacomberMap.Common.User_Interfaces.Network_Map;
using System.Collections;

namespace MacomberMap.Common.Types
{
    /// <summary>
    /// This class holds the information on a user's view, including what items are shown/set.
    /// </summary>
    public class MM_View: MM_Serializable
    {
        #region Variable declarations
        /// <summary>The default active view</summary>
        public static MM_View DefaultView;

        /// <summary>Our collection of views</summary>
        public static Dictionary<String, MM_View> Views = new Dictionary<string,MM_View>(20);

        /// <summary>Our list of view parameters for this particular view</summary>
        private List<MM_View_Parameter> ViewParameters;

        /// <summary>The full path name of the view</summary>
        public String Name;

        /// <summary>The ID for this view</summary>
        public int Index;

        /// <summary>Whether the user has access to this item</summary>
        public bool Permitted;        
        #endregion

        #region Initialization
        /// <summary>
        /// Initialize a new view based on our data reader
        /// </summary>
        /// <param name="DataReader"></param>
        public MM_View(DbDataReader DataReader): base(DataReader)
        {
            
        }

        /// <summary>
        /// Retrieve the access permissions for this view by the current role
        /// </summary>
        public String ViewAccess
        {
            set { Permitted = value[MM_User.RoleID] == '1'; }
        }

        /// <summary>
        /// Retrieve the parameters for this view
        /// </summary>
        public String ViewParams
        {
            set
            {
                ViewParameters = new List<MM_View_Parameter>();
                String InLine;
                using (StringReader sRd = new StringReader(value))
                    while (!String.IsNullOrEmpty(InLine = sRd.ReadLine()))
                        try
                        {
                            ViewParameters.Add(new MM_View_Parameter(InLine.Split('=')[0], InLine.Split('=')[1]));
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Error processing parameter " + InLine + ": " + ex.Message);
                        }
                ViewParameters.TrimExcess();
            }
        }
        #endregion

        #region Activation
        /// <summary>
        /// Activate the specified view
        /// </summary>
        public void Activate()
        {
            foreach (MM_View_Parameter Param in ViewParameters)
                Param.Assign();
        }
        #endregion

        /// <summary>
        /// This class holds the information on a view parameter
        /// </summary>
        public class MM_View_Parameter
        {
            #region Variable declarations
            /// <summary>The source for this item</summary>
            public Object SourceObject;

            /// <summary>The property assigned to this item</summary>
            public Object SourceProperty;

            /// <summary>The target value for this item</summary>
            public Object TargetValue;            
            #endregion

            #region Initialization
            /// <summary>
            /// Initialize a new parameter
            /// </summary>
            /// <param name="Source">The source for this item</param>
            /// <param name="TargetValue">Our outgoing values</param>
            public MM_View_Parameter(String Source, String TargetValue)
            {
                //First, determine our target
                String[] splStr = Source.Split('.');
                SourceObject = LocateObject(splStr[0]);

                //Now, keep propigating through until we find our target item
                for (int a = 1; a < splStr.Length - 1; a++)
                    SourceObject = LocateNextObject(SourceObject, splStr[a]);

                //Now run our last one, without updating the object
                System.Collections.IDictionary IDict = (SourceObject as System.Collections.IDictionary);

                if (IDict != null)
                {
                    Type[] DictType = IDict.GetType().GetGenericArguments();                    
                    Object Key = MM_Serializable.RetrieveConvertedValue(DictType[0], splStr[splStr.Length - 1]);
                    Object Value = MM_Serializable.RetrieveConvertedValue(DictType[1], TargetValue);
                    this.TargetValue = new KeyValuePair<Object, Object>(Key,Value);
                    
                }
                else
                {
                    LocateNextObject(SourceObject, splStr[splStr.Length - 1]);

                    //Now convert our target value to its intended result
                    if (SourceProperty is PropertyInfo)
                        this.TargetValue = MM_Serializable.RetrieveConvertedValue((SourceProperty as PropertyInfo).PropertyType, TargetValue);
                    else if (SourceProperty is FieldInfo)
                        this.TargetValue = MM_Serializable.RetrieveConvertedValue((SourceProperty as FieldInfo).FieldType, TargetValue);
                    else
                        Console.WriteLine("View: Unable to find " + splStr[splStr.Length - 1]);
                }
            }

            /// <summary>
            /// Search through an object's children (fields and properties to find our next type)
            /// </summary>
            /// <param name="PriorObject"></param>
            /// <param name="NextObject"></param>
            /// <returns></returns>
            private Object LocateNextObject(Object PriorObject, string NextObject)
            {

                FieldInfo fI;
                if (PriorObject is Type)
                    fI = (PriorObject as Type).GetField(NextObject);
                else
                    fI = PriorObject.GetType().GetField(NextObject);
                if (fI != null)
                {
                    SourceProperty = fI;
                    return fI.GetValue(SourceObject);                                       
                }

                PropertyInfo pI;
                if (PriorObject is Type)
                    pI = (PriorObject as Type).GetProperty(NextObject);
                else
                    pI = PriorObject.GetType().GetProperty(NextObject);
                if (pI != null)
                {                    
                    SourceProperty = pI;
                    return pI.GetValue(SourceObject, null);
                }
                //throw new NotSupportedException("Unable to locate object " + NextObject + " under type " + PriorObject.GetType().Name); 
                return null;
            }

            /// <summary>
            /// Search through our parameters to locate an object
            /// </summary>
            /// <param name="ObjectToLocate">The object to be located</param>
            /// <returns></returns>
            private Object LocateObject(String ObjectToLocate)
            {
                if (ObjectToLocate == "Overall")
                {
                    SourceObject = typeof(MM_Overall_Display);
                    return typeof(MM_Overall_Display);

                }
                else if (ObjectToLocate == "NetworkMap" && MM_NetworkMap.DefaultDisplayOptions == null)
                    return (MM_NetworkMap.DefaultDisplayOptions = new MacomberMap.Common.User_Interfaces.Network_Map.Components.MM_NetworkMap_Display(0, 0, 0));
                else if (ObjectToLocate == "NetworkMap")
                    return MM_NetworkMap.DefaultDisplayOptions;
                else if (MM_Overall_Display.KVLevels.ContainsKey(ObjectToLocate))
                    return MM_Overall_Display.KVLevels[ObjectToLocate];
                else if (MM_Overall_Display.EventTypes.ContainsKey(ObjectToLocate))
                    return MM_Overall_Display.EventTypes[ObjectToLocate];
                else if (MM_Overall_Display.ElemTypes.ContainsKey(ObjectToLocate))
                    return MM_Overall_Display.ElemTypes[ObjectToLocate];
                else if (ObjectToLocate.EndsWith("s") && MM_Overall_Display.ElemTypes.ContainsKey(ObjectToLocate.Substring(0, ObjectToLocate.Length-1)))
                    return MM_Overall_Display.ElemTypes[ObjectToLocate.Substring(0, ObjectToLocate.Length - 1)];
                return null;
            }

            #endregion

            #region Parameter assignment
            /// <summary>
            /// Assign the new value for this parameter
            /// </summary>
            public void Assign()
            {
                if (SourceObject is IDictionary)
                {
                    KeyValuePair<object, object> OutObj = (KeyValuePair<object, object>)TargetValue;
                    (SourceObject as IDictionary).Add(OutObj.Key, OutObj.Value);
                }
                else if (SourceProperty is FieldInfo)
                    (SourceProperty as FieldInfo).SetValue(SourceObject, TargetValue);
                else if (SourceProperty is PropertyInfo)
                    (SourceProperty as PropertyInfo).SetValue(SourceObject, TargetValue, null);
            }
            #endregion

            #region Display
            /// <summary>
            /// Provide a debugger-friendly description
            /// </summary>
            /// <returns></returns>
            public override string ToString()
            {
                if (SourceProperty is FieldInfo)
                    return SourceObject.ToString() + "." + (SourceProperty as FieldInfo).Name + "=" + TargetValue.ToString();
                else if (SourceProperty is PropertyInfo)
                    return SourceObject.ToString() + "." + (SourceProperty as PropertyInfo).Name + "=" + TargetValue.ToString();
                else 
                    return base.ToString();
            }
            #endregion
        }




    }
}
